#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

//#pragma comment(lib, "advapi32")
/*http://www.xfocus.net/articles/200408/721.html*/

#define NTAPI       __stdcall
#define FCHK(a)     if (!(a)) {printf(#a " failed\n"); return 0;}

typedef int NTSTATUS;

typedef enum _SYSDBG_COMMAND
{
    SysDbgSysReadIoSpace = 14,
    SysDbgSysWriteIoSpace = 15
}SYSDBG_COMMAND, *PSYSDBG_COMMAND;

typedef NTSTATUS (NTAPI * PZwSystemDebugControl) (
    SYSDBG_COMMAND ControlCode,
    PVOID InputBuffer,
    ULONG InputBufferLength,
    PVOID OutputBuffer,
    ULONG OutputBufferLength,
    PULONG ReturnLength
);

PZwSystemDebugControl ZwSystemDebugControl = NULL;

typedef struct _IO_STRUCT
{
    DWORD IoAddr;       // IN: Aligned to NumBYTEs,I/O address
    DWORD Reserved1;    // Never accessed by the kernel
    PVOID pBuffer;      // IN (write) or OUT (read): Ptr to buffer
    DWORD NumBYTEs;     // IN: # BYTEs to read/write. Only use 1, 2, or 4.
    DWORD Reserved4;    // Must be 1
    DWORD Reserved5;    // Must be 0
    DWORD Reserved6;    // Must be 1
    DWORD Reserved7;    // Never accessed by the kernel
}IO_STRUCT, *PIO_STRUCT;

BOOL EnablePrivilege (PCSTR name)
{
    HANDLE hToken;
    BOOL rv;
    
    TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };
    LookupPrivilegeValue (
        0,
        name,
        &priv.Privileges[0].Luid
    );
    
    OpenProcessToken(
        GetCurrentProcess (),
        TOKEN_ADJUST_PRIVILEGES,
        &hToken
    );
    
    AdjustTokenPrivileges (
        hToken,
        FALSE,
        &priv,
        sizeof priv,
        0,
        0
    );
    rv = GetLastError () == ERROR_SUCCESS;
    
    CloseHandle (hToken);
    return rv;
}

BYTE InPortB (int Port)
{
    BYTE Value;
    IO_STRUCT io;
    NTSTATUS status;
    
    io.IoAddr = Port;
    io.Reserved1 = 0;
    io.pBuffer = (PVOID) (PULONG) &Value;
    io.NumBYTEs = sizeof (BYTE);
    io.Reserved4 = 1;
    io.Reserved5 = 0;
    io.Reserved6 = 1;
    io.Reserved7 = 0;
    
    status = ZwSystemDebugControl 
    (
        SysDbgSysReadIoSpace,
          &io,
          sizeof (io),
          NULL,
          0,
          NULL
    );
    
    printf("ZwSystemDebugControl_returns#%0x\n", status);
    return Value;
}

void OutPortB (int Port, BYTE Value)
{
    IO_STRUCT io;
    NTSTATUS status;
    
    io.IoAddr = Port;
    io.Reserved1 = 0;
    io.pBuffer = (PVOID) (PULONG) & Value;
    io.NumBYTEs = sizeof (BYTE);
    io.Reserved4 = 1;
    io.Reserved5 = 0;
    io.Reserved6 = 1;
    io.Reserved7 = 0;
    
    status = ZwSystemDebugControl 
    (
        SysDbgSysWriteIoSpace,
        &io,
        sizeof (io),
        NULL,
        0,
        NULL
    );
    
    printf("ZwSystemDebugControl_returns#%0x\n", status);
};

void BeepOn (int Freq)
{
    BYTE b;

    if ((Freq >= 20) && (Freq <= 20000))
    {
        Freq = 1193181 / Freq;
        b = InPortB (0x61);
        if ((b & 3) == 0)
    {
        OutPortB (0x61, (BYTE) (b | 3));
        OutPortB (0x43, 0xb6);
    }
        OutPortB (0x42, (BYTE) Freq);
        OutPortB (0x42, (BYTE) (Freq >> 8));
    }
}

void BeepOff (void)
{
    BYTE b;

    b = (InPortB (0x61) & 0xfc);
    OutPortB (0x61, b);
}

int main (void)
{
    HMODULE hNtdll;
    ULONG ReturnLength;
    OSVERSIONINFO OSVersionInfo;
    OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);

    EnablePrivilege (SE_DEBUG_NAME);

    FCHK ((hNtdll = LoadLibrary ("ntdll.dll")) != NULL);
    FCHK ((ZwSystemDebugControl = (PZwSystemDebugControl) 
           GetProcAddress (hNtdll, "ZwSystemDebugControl")) != NULL);
    FCHK ((void *) GetVersionEx (&OSVersionInfo) != NULL);

    if (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
        OSVersionInfo.dwMajorVersion >= 5 &&
        OSVersionInfo.dwMinorVersion >= 1)
    {
        BeepOn (2000);
        Sleep (1000);
        BeepOff ();
    }
    else
    {
        printf ("This program require Windows XP or Windows 2003.\n");
    }
    
    system("pause");
    return 0;
}
